// Copyright 2007-2010 Comdiv (F. Sadykov) - http://code.google.com/u/fagim.sadykov/
// Supported by Media Technology LTD 
//  
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//  
//      http://www.apache.org/licenses/LICENSE-2.0
//  
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// 
// MODIFICATIONS HAVE BEEN MADE TO THIS FILE
using System;
using System.Collections.Generic;
using System.IO;
using System.Security.Principal;
using System.Xml.Linq;
using System.Xml.XPath;
using Comdiv.Application;
using Comdiv.Collections;
using Comdiv.Extensions;
using Comdiv.Inversion;

namespace Comdiv.Security{
    ///<summary>
    ///</summary>
    public static class RoleResolverExtensions{
        public static object sync = new object();
        private static IPrincipalSource _principalSource;
        private static IInversionContainer _container;
        public static IInversionContainer Container
        {
            get
            {
                if (_container.invalid())
                {
                    lock (sync)
                    {
                        if (_container.invalid())
                        {
                            Container = myapp.ioc;
                        }
                    }
                }
                return _container;
            }
            set { _container = value; }
        }
        ///<summary>
        ///</summary>
        public static IPrincipalSource PrincipalSource
        {
            get
            {
                if (_principalSource == null)
                {
                    _principalSource = Container.get<IPrincipalSource>() ?? new DefaultPrincipalSource();
                }
                return _principalSource;
            }
            set { _principalSource = value; }
        }
        public static bool IsInRole(this IRoleResolver resolver,string role){
            if (null == resolver) return getCurrent().IsInRole(role);
            return resolver.IsInRole(getCurrent(), role, true);
        }
        public static bool IsInRole(this IRoleResolver resolver,IPrincipal principal, string role)
        {
            if (null == resolver) return principal.IsInRole(role);
            return resolver.IsInRole(principal, role, true);
        }

        private static IPrincipal getCurrent(){
            return PrincipalSource.Current;
        }

        public static bool IsAdmin(this IRoleResolver resolver){
            return IsAdmin(resolver, getCurrent());
        }

        public static bool IsAdmin(this IRoleResolver resolver, IPrincipal user){
            return resolver.IsInRole(user, "ADMIN");
        }
        public static IEnumerable<string> GetRoles(this IRoleResolver resolver){
            return resolver.GetRoles(getCurrent());
        }
        public static void AssignToRole(this IRoleResolver resolver, string user, string role){
            resolver.AssignToRole(user,role,true);
        }
        public static void SetupDefaults(this IExtendedRoleResolver resolver)
        {
            SetupDefaults(resolver, String.Empty);
        }

        public static void SetupDefaults(this IExtendedRoleResolver resolver, string filename)
        {
            if (resolver.SourceFile.noContent()){
                if (filename.noContent()){
                    foreach (var root in new[]{"~/usr/", "~/sys/", "~/"}){
                        var file = (root + "security.map.config").mapPath();
                        if (File.Exists(file)){
                            filename = file;
                            break;
                        }

                    }
                }
                resolver.SourceFile = filename;
            }
            if(filename.noContent()){
                filename = resolver.SourceFile;
            }
            resolver.ApplicationRoles = new List<string> { "ADMIN", "DEVELOPER", "LEADER", "CONTROLLER", "OPERATOR", "DEFAULT" };
            resolver.UserMap = new StringMap();
            resolver.RoleMap = new StringMap();
            if (filename.hasContent())
            {
                LoadMappingsFromFile(resolver, resolver.SourceFile);
            }
        }

        private static void LoadMappingsFromFile(this IExtendedRoleResolver resolver, string file)
        {
            var x = XElement.Load(file);
            loadApplicationRoles(resolver, x);
            loadMaps(resolver, x);
        }

        private static void loadMaps(this IExtendedRoleResolver resolver, XElement element)
        {
            resolver.UserMap.Clear();
            var userMaps = element.XPathSelectElements("//map[@user]");
            foreach (var map in userMaps)
            {
                resolver.UserMap.Add(map.get("user", String.Empty), map.get("as", String.Empty));
            }

            resolver.RoleMap.Clear();
            var roleMaps = element.XPathSelectElements("//map[@role]");
            foreach (var map in roleMaps)
            {
                resolver.RoleMap.Add(map.get("role", String.Empty), map.get("as", String.Empty));
            }
        }

        private static void loadApplicationRoles(this IExtendedRoleResolver resolver, XElement element)
        {

            resolver.ApplicationRoles = new List<string> { "ROOT", "ADMIN", "DEVELOPER", "LEADER", "CONTROLLER", "OPERATOR", "DEFAULT" };
            var roles = element.XPathSelectElements("//role");
            foreach (var role in roles)
            {

                
                string roleName = role.get("name", String.Empty);
                
                if (!resolver.ApplicationRoles.Contains(roleName))
                {
                    resolver.ApplicationRoles.Add( roleName);
                }
                
            }



        }

    }
}